package com.ljf.daily.consumptiondetail.domain.service;

import com.ljf.common.domain.service.BasisDomainService;
import com.ljf.common.exception.ServiceException;
import com.ljf.common.utils.CollectionUtil;
import com.ljf.common.utils.DateUtil;
import com.ljf.common.utils.StringUtil;
import com.ljf.config.domain.service.DailyConfigDatKeyValueDomainService;
import com.ljf.config.enums.DailyConfigDatKeyValueEnum;
import com.ljf.daily.consumptiondetail.domain.repository.DailyDatConsumptionDetailRepository;
import com.ljf.daily.costmanagement.domain.service.DailyDatCostManagementDomainService;
import com.ljf.daily.makemoneydetail.domain.service.DailyDatMakeMoneyDetailDomainService;
import com.ljf.daily.consumptiondetail.dto.command.DailyDatConsumptionDetailCommand;
import com.ljf.daily.consumptiondetail.dto.command.DailyDatConsumptionDetailGenerateDataCommand;
import com.ljf.daily.makemoneydetail.dto.command.DailyDatMakeMoneyDetailCommand;
import com.ljf.daily.consumptiondetail.dto.query.DailyDatConsumptionDetailQuery;
import com.ljf.daily.consumptiondetail.enums.DailyDatConsumptionDetailStatusEnum;
import com.ljf.daily.consumptiondetail.model.DailyDatConsumptionDetail;
import com.ljf.daily.makemoneydetail.model.DailyDatMakeMoneyDetail;
import com.ljf.daily.consumptiondetail.vo.DailyDatConsumptionDetailEditDataVO;
import com.ljf.daily.consumptiondetail.vo.DailyDatConsumptionDetailVO;
import com.ljf.daily.makemoneydetail.vo.DailyDatMakeMoneyDetailVO;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.sql.rowset.serial.SerialException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 日常消费明细  领域服务
 *
 * @author LJF
 * @since 2024-05-15
 */
@Component
public class DailyDatConsumptionDetailDomainService extends BasisDomainService<DailyDatConsumptionDetailRepository, DailyDatConsumptionDetailQuery, DailyDatConsumptionDetailVO, DailyDatConsumptionDetail, DailyDatConsumptionDetailCommand> {

    @Resource
    private DailyConfigDatKeyValueDomainService dailyConfigDatKeyValueDomainService;

    @Resource
    private DailyDatMakeMoneyDetailDomainService makeMoneyDetailDomainService;

    @Resource
    private DailyDatCostManagementDomainService costManagementDomainService;

    @Override
    public Boolean edit(DailyDatConsumptionDetailCommand command) throws ServiceException {
        DailyDatConsumptionDetailVO todayDetail = this.queryById(command.getId());
        DailyDatConsumptionDetailEditDataVO editData = this.editData(todayDetail.getBelongDate(), command.getDayConsumption());
        command.setAllocationAmount(editData.getAllocationAmount());
        command.setTotalBalance(editData.getTotalBalance());
        command.setDayBalance(editData.getDayBalance());
        super.edit(command);
        List<String> allocationSoftware = dailyConfigDatKeyValueDomainService.getListByKey(DailyConfigDatKeyValueEnum.CONSUMPTION_DETAIL_TARGET_SOFTWARE);
        if (editData.getAllocationAmountNum().compareTo(BigDecimal.ZERO) != 0) {
            for (String software : allocationSoftware) {
                makeMoneyDetailDomainService.add(
                        DailyDatMakeMoneyDetailCommand.builder()
                                .softwareCode(software)
                                .withdrawalCount(editData.getAllocationAmountNum())
                                .belongDate(todayDetail.getBelongDate())
                                .remark("")
                                .build()
                );
            }
        }
        String originSoftware = dailyConfigDatKeyValueDomainService.getStringByKey(DailyConfigDatKeyValueEnum.CONSUMPTION_DETAIL_ORIGIN_SOFTWARE);
        makeMoneyDetailDomainService.add(
                DailyDatMakeMoneyDetailCommand.builder()
                        .softwareCode(originSoftware)
                        .withdrawalCount(todayDetail.getPlannedAmount().multiply(new BigDecimal("-1")))
                        .belongDate(todayDetail.getBelongDate())
                        .remark("")
                        .build()
        );
        BigDecimal middleBigDecimal = command.getTotalBalance().subtract(editData.getAllocationAmountNum().multiply(new BigDecimal(allocationSoftware.size())));
        String middleSoftware = dailyConfigDatKeyValueDomainService.getStringByKey(DailyConfigDatKeyValueEnum.CONSUMPTION_DETAIL_MIDDLE_SOFTWARE);
        if (middleBigDecimal.compareTo(BigDecimal.ZERO) != 0) {
            makeMoneyDetailDomainService.add(
                    DailyDatMakeMoneyDetailCommand.builder()
                            .softwareCode(middleSoftware)
                            .withdrawalCount(middleBigDecimal)
                            .belongDate(todayDetail.getBelongDate())
                            .remark("")
                            .build()
            );
        }
        List<DailyDatMakeMoneyDetailVO> yesterdayMakeMoneyList = makeMoneyDetailDomainService.queryList(middleSoftware, DateUtil.addDate(todayDetail.getBelongDate(), -1));
        List<Long> yesterdayIds = yesterdayMakeMoneyList.stream()
                .filter(one -> one.getWithdrawalCount().compareTo(BigDecimal.ZERO) < 0)
                .map(DailyDatMakeMoneyDetail::getId)
                .collect(Collectors.toList());
        if (CollectionUtil.isNotEmpty(yesterdayIds)) {
            makeMoneyDetailDomainService.deleteBatch(yesterdayIds);
        }
        return true;
    }

    /**
     * 生成数据接口
     *
     * @param command
     * @return
     * @throws SerialException
     */
    public Integer generateData(DailyDatConsumptionDetailGenerateDataCommand command) throws ServiceException {
        Set<String> holiday = new HashSet<>();
        if (CollectionUtil.isNotEmpty(command.getSpecialDate())) {
            for (Date date : command.getSpecialDate()) {
                holiday.add(DateUtil.formatDate(date));
            }
        }
        Calendar instance = Calendar.getInstance();
        instance.setTime(command.getEndDate());
        Date startDate = command.getStartDate();
        boolean last, last2;
        int current;
        List<DailyDatConsumptionDetail> resultList = new ArrayList<>();
        while (instance.getTime().getTime() >= startDate.getTime()) {
            current = 0;
            last = instance.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY || instance.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY || instance.get(Calendar.DAY_OF_WEEK) == Calendar.FRIDAY;
            last2 = holiday.contains(DateUtil.formatDate(instance.getTime()));
            if (last && last2) {
                current = current + 50 + 50 + 20 + 60;
            }
            else if (last) {
                current = current + 50 + 50 + 20;
            }
            else if (last2) {
                current = current + 50 + 20 + 40;
            }
            else {
                current = current + 50 + 20;
            }
            resultList.add(
                    DailyDatConsumptionDetail.builder()
                            .belongDate(instance.getTime())
                            .plannedAmount(new BigDecimal(current))
                            .dayBalance(BigDecimal.ZERO)
                            .totalBalance(BigDecimal.ZERO)
                            .allocationAmount("")
                            .remark("")
                            .status(DailyDatConsumptionDetailStatusEnum.NOT_FINISH.getCode())
                            .build()
            );
            instance.add(Calendar.DATE, -1);
        }
        int execCount = 0;
        for (int i = resultList.size() - 1; i >= 0; i--) {
            DailyDatConsumptionDetail detail = resultList.get(i);
            repository.insert(detail);
            execCount++;
        }
        return execCount;
    }

    /**
     * 获取更新数据
     *
     * @param date
     * @param dayConsumption
     * @return
     * @throws ServiceException
     */
    public DailyDatConsumptionDetailEditDataVO editData(Date date, String dayConsumption) throws ServiceException {
        DailyDatConsumptionDetailEditDataVO result = new DailyDatConsumptionDetailEditDataVO();
        DailyDatConsumptionDetailVO todayDetail = repository.selectOne(
                DailyDatConsumptionDetailQuery.builder().belongDate(date).build()
        );
        BigDecimal todayConsumption = BigDecimal.ZERO;
        if (StringUtil.isNotEmpty(dayConsumption)) {
            for (String s : dayConsumption.trim().split("\\s+")) {
                todayConsumption = todayConsumption.add(new BigDecimal(s));
            }
        }
        List<BigDecimal> costList = costManagementDomainService.queryDayCost(date);
        BigDecimal temp = new BigDecimal("-1");
        for (BigDecimal decimal : costList) {
            todayConsumption = todayConsumption.add(decimal.multiply(temp));
        }
        BigDecimal dayBalance = todayDetail.getPlannedAmount().subtract(todayConsumption);
        result.setDayBalance(dayBalance);
        Date yesterday = DateUtil.addDate(date, -1);
        DailyDatConsumptionDetailVO yesterdayDetail = repository.selectOne(
                DailyDatConsumptionDetailQuery.builder().belongDate(yesterday).build()
        );
        if (yesterdayDetail != null && yesterdayDetail.getTotalBalance().compareTo(BigDecimal.ZERO) < 0) {
            result.setTotalBalance(dayBalance.add(yesterdayDetail.getTotalBalance()));
        }
        else {
            result.setTotalBalance(dayBalance);
        }
        List<String> allocationSoftware = dailyConfigDatKeyValueDomainService.getListByKey(DailyConfigDatKeyValueEnum.CONSUMPTION_DETAIL_TARGET_SOFTWARE);
        if (result.getTotalBalance().compareTo(BigDecimal.ZERO) <= 0) {
            result.setAllocationAmount(String.format("0*%s=0", allocationSoftware.size()));
            result.setAllocationAmountNum(BigDecimal.ZERO);
        }
        else {
            int num = allocationSoftware.size() + 1;
            BigDecimal allocationAmount = result.getTotalBalance().divide(BigDecimal.valueOf(num), 2, RoundingMode.DOWN);
            BigDecimal allocationTotalAmount = allocationAmount.multiply(BigDecimal.valueOf(allocationSoftware.size()));
            result.setAllocationAmount(String.format("%s*%s=%s", allocationAmount, allocationSoftware.size(), allocationTotalAmount));
            result.setAllocationAmountNum(allocationAmount);
        }
        return result;
    }

    @Override
    public DailyDatConsumptionDetailVO queryById(Long id) throws ServiceException {
        DailyDatConsumptionDetailVO vo = super.queryById(id);
        // 费用明细
        List<BigDecimal> costList = costManagementDomainService.queryDayCost(vo.getBelongDate());
        StringBuilder dayCost = new StringBuilder();
        BigDecimal temp = new BigDecimal("-1");
        BigDecimal costDecimal = BigDecimal.ZERO;
        for (BigDecimal decimal : costList) {
            dayCost.append(decimal.multiply(temp)).append(" ");
            costDecimal = costDecimal.add(decimal);
        }
        vo.setDayCost(dayCost.toString());
        // 第二次修改
        if (StringUtil.isNotEmpty(vo.getAllocationAmount())) {
            vo.setDayConsumption(vo.getPlannedAmount().subtract(vo.getDayBalance()).add(costDecimal));
        }
        return vo;
    }
}
